package com.jun.common.redis.config;

import com.jun.common.redis.properties.RedisClusterProperties;
import com.jun.common.redis.properties.RedisTemplateProperties;
import io.lettuce.core.ReadFrom;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStaticMasterReplicaConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

import javax.annotation.PostConstruct;

/**
 * @author yuejun.li
 * @date 2024/7/26 14:40:26
 * redis的主从、分片集群配置
 */
@Slf4j
@Configuration
@EnableConfigurationProperties({RedisTemplateProperties.class})
public class RedisClusterConfig {

    @PostConstruct
    public void init() {
        log.info("Redis successful!");
    }

    /**
     * 配置redis模板和序列化
     * @param factory
     * @param properties
     * @return
     */
    @Bean
    @Primary
    public RedisTemplate redisTemplate(RedisConnectionFactory factory, RedisTemplateProperties properties) {
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(factory);
        properties.serialization(redisTemplate);
        return redisTemplate;
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.redis.master-slave")
    public RedisClusterProperties redisMasterSlaveProperties() {
        return new RedisClusterProperties();
    }


    @Bean("clusterLettuceConnectionFactory")
    public RedisConnectionFactory lettuceConnectionFactory(RedisClusterProperties redisClusterProperties) {
        // 解析主节点
        String[] masterParts = redisClusterProperties.getMaster().split(":");
        RedisStaticMasterReplicaConfiguration masterReplicaConfig = new RedisStaticMasterReplicaConfiguration(
                masterParts[0], Integer.parseInt(masterParts[1])
        );
        masterReplicaConfig.setPassword(redisClusterProperties.getPassword());

        // 添加从节点
        for (String slave : redisClusterProperties.getSlaves()) {
            String[] parts = slave.split(":");
            masterReplicaConfig.addNode(parts[0], Integer.parseInt(parts[1]));
        }
        // 配置Lettuce客户端与读取策略
        LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder()
                // 读写分离,这里的ReadFrom是配置Redis的读取策略,是一个枚举,包括下面选择
                // MASTER   仅读取主节点
                // MASTER_PREFERRED   优先读取主节点,如果主节点不可用,则读取从节点
                // REPLICA_PREFERRED   优先读取从节点,如果从节点不可用,则读取主节点
                // REPLICA   仅读取从节点
                // NEAREST   从最近节点读取
                // ANY   从任意一个从节点读取
                .readFrom(ReadFrom.REPLICA_PREFERRED)
                .build();

        return new LettuceConnectionFactory(masterReplicaConfig, lettuceClientConfiguration);
    }

}
